package com.kfm.kfmspringboot.controller.handler;

import com.kfm.kfmspringboot.controller.ex.ServerException;
import com.kfm.kfmspringboot.model.response.ResponseCode;
import com.kfm.kfmspringboot.model.response.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 * 使用form-data方式调用接口，校验异常抛出 BindException
 * 使用 json 请求体调用接口，校验异常抛出 MethodArgumentNotValidException
 * 单个参数校验异常抛出ConstraintViolationException
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理 json 请求体调用接口校验失败抛出的异常
     *
     * @param ex 程序执行发生的异常
     * @return 响应实体对象
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
        List<String> collect = fieldErrors.stream().map(o -> o.getDefaultMessage()).collect(Collectors.toList());
        return ResultVO.failure(ResponseCode.VALIDATE_ERROR_CODE, "参数校验错误", collect.toString());
    }

    /**
     * 处理使用 form-data 方式调用接口，校验异常抛出 BindException
     *
     * @param ex 程序执行发生的异常
     * @return 响应实体对象
     */
    @ExceptionHandler(BindException.class)
    public ResultVO<String> handleBindException(BindException ex) {
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
        List<String> collect = fieldErrors.stream().map(o -> o.getDefaultMessage()).collect(Collectors.toList());
        return ResultVO.failure(ResponseCode.VALIDATE_ERROR_CODE, "参数校验错误", collect.toString());
    }

    /**
     * 系统异常预期以外异常
     * @param ex 程序执行发生的异常
     * @return 响应实体对象
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultVO<String> handleUnexpectedServer(Exception ex) {
        log.error("系统异常：", ex);
        return ResultVO.failure(ex.getMessage());
    }

    /**
     * 所有异常的处理
     * @param ex 程序执行发生的异常
     * @return 响应实体对象
     */
    @ExceptionHandler(Throwable.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultVO<String> exception(Throwable ex) {
        log.error("系统异常：", ex);
        return ResultVO.failure(ex.getMessage());
    }

    /**
     * 处理自定义的异常信息
     * @param ex 程序执行发生的异常
     * @return 响应实体对象
     */
    @ExceptionHandler(ServerException.class)
    public ResultVO<String> APIExceptionHandler(ServerException ex) {
        return ResultVO.failure(ex.getCode(), ex.getMsg());
    }
}

